package service.temp.job.matching.poc.listingapi.feign;

import feign.Logger;
import feign.Request;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.slf4j.Slf4jLogger;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.feign.FeignDecorators;
import io.github.resilience4j.feign.Resilience4jFeign;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
import lombok.experimental.UtilityClass;
import service.temp.job.matching.poc.listingapi.utils.JsonUtils;

import java.time.Duration;
import java.util.function.Function;


/**
 * FeignClientApiBuilder
 *
 * @author Chao Xiong (chxiong@coupang.com)
 */
@UtilityClass
public class FeignClientApiBuilder {


    private static final String API_GATEWAY_URL = "https://api-gateway.coupang.net";

    public static <T> T buildFeignClientApi(Class<T> clazz, String consumerToken,
                                            int timeoutMS, RateLimiterConfig rateLimiterConfig, Function<Exception, T> fallbackFactory) {
        RateLimiter rateLimiter = RateLimiter.of(clazz.getName(), rateLimiterConfig);

        CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .waitDurationInOpenState(Duration.ofMillis(2_000))
                .build();
        CircuitBreaker circuitBreaker = CircuitBreaker.of(clazz.getName(), circuitBreakerConfig);

        // call --> circuit breaker --> rate limiter --> feign
        FeignDecorators decorators = FeignDecorators.builder()
                .withRateLimiter(rateLimiter)
                .withCircuitBreaker(circuitBreaker)
                .withFallbackFactory(fallbackFactory)
                .build();

        return Resilience4jFeign.builder(decorators)
                .logger(new Slf4jLogger())
                .logLevel(Logger.Level.FULL)
                .encoder(new JacksonEncoder(JsonUtils.mapper()))
                .decoder(new JacksonDecoder(JsonUtils.mapper()))
                .requestInterceptor(new ApiGatewayInterceptor(consumerToken))
                .options(new Request.Options(10_000, timeoutMS))
                .target(clazz, API_GATEWAY_URL);
    }
}
